package top.xia17.plugins.fast.auth.login;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import top.xia17.plugins.fast.common.autoconfiguration.TokenProperties;
import top.xia17.plugins.fast.common.database.redis.RedisUtils;
import top.xia17.plugins.fast.common.exceptions.BadRequestException;
import top.xia17.plugins.fast.common.mail.Xia17MailUtil;
import top.xia17.plugins.fast.common.security.token.provider.TokenProvider;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import top.xia17.plugins.fast.auth.autoconfiguraion.AuthProperties;
import top.xia17.plugins.fast.auth.model.AuthConstant;
import top.xia17.plugins.fast.auth.model.req.EmailLoginReq;
import top.xia17.plugins.fast.user.model.dto.UserDto;
import top.xia17.plugins.fast.user.service.UserService;

import java.util.HashMap;
import java.util.concurrent.TimeUnit;

/**
 * 邮箱登录帮助类
 * 将邮箱登录相关的一些方法封装在此
 * @author xia17
 */
@Service
@Slf4j
public class EmailLoginHelper extends AbstractLoginHelper<EmailLoginReq> {

    private final static String CODE_REDIS_KEY = "email_login_code_";
    private final static String CODE_LIMIT_REDIS_KEY = "email_login_code_limit_";
    private final static String DEFAULT_MSG_TEMPLATE = "你本次的登录验证码是{code},有效时间{time}分钟！";

    private final UserService userService;
    private final RedisUtils redisUtils;
    private final Xia17MailUtil mailUtil;
    private final AuthProperties authProperties;


    public EmailLoginHelper(AuthProperties authProperties, RedisUtils redisUtils,
                            UserService userService, TokenProvider tokenProvider,
                            TokenProperties tokenProperties , Xia17MailUtil xia17MailUtil) {
        super(authProperties, redisUtils, userService, tokenProvider, tokenProperties);
        this.userService = userService;
        this.redisUtils = redisUtils;
        this.mailUtil = xia17MailUtil;
        this.authProperties = authProperties;
    }

    @Override
    public String getLoginMethodName() {
        return AuthConstant.EMAIL_LOGIN_METHOD;
    }

    @Override
    public String getNotSupportErrorMessage() {
        return "系统已关闭邮箱登录方式，请尝试其他登录方式！";
    }

    @Override
    public UserDto verifyUser(EmailLoginReq req) {
        UserDto user = userService.getByEmail(req.getEmail()).orElseThrow(() -> new BadRequestException(
                "邮箱号不存在!"));
        // 验证邮箱code是否正确
        this.verifyEmailCode(req);
        return user;
    }


    /**
     * 验证邮箱验证码是否正确
     * @param req 请求信息
     */
    public void verifyEmailCode(EmailLoginReq req){
        String uuid = req.getUuid();
        String email = req.getEmail();
        String code = req.getEmailLoginCode();
        Object obj = redisUtils.get(CODE_REDIS_KEY + uuid);
        if (obj == null){
            throw new BadRequestException("验证码已失效！");
        }
        CodeObj codeObj = (CodeObj) obj;
        if (!codeObj.getCode().equals(code)){
            throw new BadRequestException("验证码错误!");
        }
        if (!codeObj.getTo().equals(email)){
            log.error("邮箱登录验证码的使用人不对，应该是{},而目前发现的使用人是{}", codeObj.getTo(), email);
            throw new BadRequestException("验证码异常，请重新发送！");
        }
    }

    /**
     * 发送邮箱验证码
     * @param email 邮件地址
     * @param ip 发起请求的ip地址
     * @return 返回uuid
     */
    public String sendEmailCode(String email , String ip){
        // 验证邮箱是否存在
        userService.getByEmail(email).orElseThrow(() -> new BadRequestException("邮箱号不存在!"));
        // 生成随机数
        String uuid = IdUtil.simpleUUID();
        String code = RandomUtil.randomNumbers(6);
        // 计算tag
        String limitTag = switch (authProperties.getLoginCodeLimitTag()) {
            case "IP" -> ip;
            case "TO" -> email;
            default -> throw new BadRequestException("xia17common.auth.login-code-limit-tag配置异常，可选值【IP,TO】");
        };
        // 是否阻止本次发送
        long expire = redisUtils.getExpire(CODE_LIMIT_REDIS_KEY + limitTag);
        if (expire > 0){
            throw new BadRequestException("请在" + expire + "秒后重新发送！");
        }
        // code存储redis
        redisUtils.set(CODE_REDIS_KEY + uuid , new CodeObj(code,email) , authProperties.getLoginCodeEffectiveTime() ,
                TimeUnit.MINUTES);
        // 限制标记存储redis
        redisUtils.set(CODE_LIMIT_REDIS_KEY + limitTag,1,authProperties.getLoginCodeLimitTime(),TimeUnit.SECONDS);
        // 构建消息,并发送
        String msgTemplate = obtainMsgTemplate();
        HashMap<String, String> params = new HashMap<>(4);
        params.put("code", code);
        params.put("time",authProperties.getLoginCodeEffectiveTime().toString());
        String content = StrUtil.format(msgTemplate, params);
        mailUtil.send(email, authProperties.getLoginCodeEmailSubject(), content, false);
        return uuid;
    }


    /**
     * 获取消息模板
     * @return /
     */
    private String obtainMsgTemplate(){
        String msgTemplate = this.authProperties.getLoginCodeEmailTemplate();
        if (StrUtil.isBlank(msgTemplate)){
            return DEFAULT_MSG_TEMPLATE;
        }
        return msgTemplate;
    }

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    private static class CodeObj {

        /**
         * 验证码
         */
        private String code;

        /** 给谁使用的 */
        private String to;

    }




}
